﻿#ifndef PANELLOCATOR_H
#define PANELLOCATOR_H
#include "qtOpenCV/TemplateMatch.h"
//#include "recipeloader.h"
#include <QString>
#include <QImage>

/**
 * @brief The PanelLocator class 算法类，用于 Panel 定位。一个 PanelLocator 对应一个 Panel
 *          如果 Stage 上有多个 Panel，那么需要多个 PanelLocator 的实例来分别定位
 *          如果 Stage 上放的 Panel 可能有多种切型。那么也需要多个 PanelLocator 的实例来判断。哪个得分高就应该用哪个的结果。
 */
class PanelLocator
{
//    friend RecipeLoader;
public:
    PanelLocator();
    bool panelDetect(QImage &image);
    bool panelDetect(const cv::Mat &grayImage);
    cv::Size panelSize(const cv::Mat &grayImage); // 计算被检测物体的尺寸。输入图像必须是 CV_8UC1
    int panelSizeDeviate(const cv::Mat &grayImage); // 计算被检测物体的尺寸与标准尺寸的偏离。输入图像必须是 CV_8UC1
    /**
     * @brief getData 获得当前 panel 的数据
     * @param [in] um_pix  传入参数，像素的尺寸, 一个像素多少 um
     * @param [out] x_mm  X 方向的偏移量， mm 为单位
     * @param [out] y_mm  Y 方向的偏移量， mm 为单位
     * @param [out] theta  角度，度为单位
     * @param [out] score  当前 Panel 的打分
     * @return true 表示匹配到了 Panel， false 表示没有匹配到 Panel。这时 x y theta 都会返回 0
     */
    bool getData(double um_pix, double &x_mm, double &y_mm, double &theta, double &score);
    cv::Point2i m_shift;// 左边 Panel 相对于标准位置的偏移量
    double m_rotateTheta = 0;
    double m_score = 0.6; // 左边 Panel 的打分
    QRect m_panelRect; // 左边 Panel 的位置。这个位置信息只是给显示界面用来画一个框的。不参与实际的计算。
private:
    /**
     * @brief panelShift 计算 Panel 的位置偏移
     * @param [in] imageGray  输入的图像，必须是灰度图像
     * @param [out] s 返回偏移值，单位为像素
     * @return 返回 1 表示成功，0 表示没有找到 Panel， -1 表示其他错误
     */
    int panelShift(const cv::Mat &imageGray, cv::Point2i &s);

    /**
     * @brief panelRotate 计算 Panel 的旋转角度，要在 panelShift 之后调用。
     * @param imageGray
     * @param theta 返回旋转角度，单位为度，逆时针为正方向。
     * @return 返回 1 表示成功，0 表示没有找到 Panel， -1 表示其他错误
     */
    int panelRotate(const cv::Mat &imageGray, double & theta);// theta 单位是度

    /**
     * @brief clear 将所有检测结果清零
     */
    void clear();

public:
    cv::Size m_panelSize;
    QString m_recipeName;
    cv::Mat m_templateFull;
    cv::Mat m_template;// 左边 Panel，会比实际的 Panel 大一些
    cv::Rect m_searchRegion;// 只在这个区域内做模板匹配
    cv::Rect m_lineSearchRegion;//寻找左边 Panel 的左边线的区域，根据左边线来确定 Panel 的旋转角度
    cv::Point2i m_panelTopLeft; // 左边 Panel 在图中的位置，左上角坐标

    double m_threshold; // 左边 Panel 的阈值，超过阈值才认为找到 Panel 了
    bool m_panelLocateFailed = false;
    bool m_valid;
};

#endif // PANELLOCATOR_H
